#ifndef __EPSILON__FONT_H__
#define __EPSILON__FONT_H__


// eFont
// The code in this class is a highly modified version of the ftgl OpenGL 
//  fonts library and code from the Freetype2 tutorial.

#include "../Epsilon/strings.h"
#include "../Epsilon/types.h"
//#include <cmath>

#include <vector>

class e3dTexture;
class e3dIndexCache;
class e3dVertexCache;

// When creating a font, you need to fill in a font info structure and pass it into the font manager.
struct eFontInfo {
  /// Name of the font or font file.
  const TCHAR* szName;

  // The height of the font in pixels.  This is not the exact height, but the size of the EM square.
  int glyphSize;

  // 1..255 are valid, but internally rounded to one of 1, 4, 16, and 64 for Microsoft fonts.
  int numAlphaShades; 
  
  bool isBold; 
  bool isItalic;
  bool isUnderline;
};



class eFont;

struct ePoint {
  float GetX (void) const { return x; }
  float GetY (void) const { return y; }

  float x, y; ///< X and Y are offsets from the top left.
};

struct eGlyphTexRect {
  int GetX       (void) const { return x; }
  int GetY       (void) const { return y; }

  int GetWidth   (void) const { return w; }
  int GetHeight  (void) const { return h; }

  void SetX      (int _x) { x = _x; }
  void SetY      (int _y) { y = _y; }

  void SetWidth  (int _w) { w = _w; }
  void SetHeight (int _h) { h = _h; }
  
  int w, h; ///< W and H are the width and height of the glyph.
  int x, y; ///< X and Y are offsets from the top left.
};

struct eTexCoord2D {
  union {
    struct {
      float u,
             v;
    };
    struct {
      float s,
             t;
    };
  };
};

struct eGlyphTexCoords {
  eTexCoord2D min; ///< Minimum (top left)
  eTexCoord2D max; ///< Maximum (bottom right)
};

struct eGlyph {
  eGlyphTexRect   rect;    ///< X,Y position and Width/Height in the texture
  eGlyphTexCoords st;      ///< Minimum / Maximum texture coordinates
  float           advance; ///< The advances for the characters; we're going
                           ///  to ignore kerning information.
  int             offset;  ///< The byte offset of this glyph into memoryTex.
                           ///   * This used to be a seaparate array, apparently
                           ///     to improve cache coherency. Consider changing
                           ///     it back if it truly does improve performance.
};

struct GlyphVertexEx
{
  float         pos   [3];
  unsigned char color [4];
  float         st    [2];
};

class eFont {
public:
public:
  //
  // Public Methods & Functions
  //

  eFont (void) : minChar     (32),
                 maxChar     (126),
                 ascent      (10.0f),
                 descent     (10.0f),
                 rowHeight   (20.0f),
                 glyphs_     (NULL),
                 texture_    (NULL),
                 refCount    (0),
                 logFileID   (-1) { }

  ~eFont (void) { Free (); }


  // TODO - printf

  // Prints 'numChars' characters from 'string' with its left-most character beginning at 'x'
  //  and the baseline of the text at 'y'.  Returns the position where the next character
  //  should be printed.  The text is rendered in immediate mode using tiny quads for each character.
  float Print (const TCHAR* szString, int numChars, float x, float y);

  /// Prints the specified null-terminated string with its left-most character beginning at
  ///  'x' and the baseline of the text at 'y'.  Returns the position where the next 
  ///  character should be printed.  x & y should be integer valued or you'll smear the font.
  /// The text is rendered in immediate mode using tiny quads for each character.
  float Print ( const TCHAR*    szString,
                float           x,
                float           y,
                e3dVertexCache* vcache,
                e3dIndexCache*  icache,
                float           scale = 1.0f );

  float   PrintToArray ( const TCHAR* szString,
                         float        x,
                         float        y,
                         DWORD        color,
                         int&         last_vert,
                         std::vector <GlyphVertexEx>&  verts,
                         std::vector <unsigned short>& indices,
                         float                         scale = 1.0f );

  void  FinishArrayPrint  ( int                           num_verts,
                            std::vector <GlyphVertexEx>&  verts,
                            std::vector <unsigned short>& indices );

  /// PrintToBuffer (...) writes a text texture representing the string to the given buffer.
  /// Assumes the buffer is large enough or larger than necessary to contain the string.
  /// If the buffer is larger, the space at the end of the buffer is left as it is, and
  /// not overwritten.  The string is assumed to be null terminated.  The buffer does not
  /// have to be zeroed beforehand - the text pixels will replace what is already there.
  /// This method only works if the memory font is loaded for this font.
  void PrintToBuffer (const TCHAR* szString, byte* pBuffer, int bufferWidth);

  /// True if the memory font associated with this texture font has been loaded.
  bool MemoryFontIsLoaded (void) { return bitmap_ != NULL; }

  /// You should always free a font after you are done with it.  Calling free on an already freed
  /// font should do nothing.
  void Free (void);

  /// Calculates the bottom Y value of a caret for this font
  float GetCaretBottom (float baseline) {
    return baseline + descent - 1.0f;  // adding a positive value moves us down
  }

  /// Calculates the top Y value of a caret for this font
  float GetCaretTop (float baseline) {
    return baseline - ascent - descent;   // subtracting moves us up
  }

  bool loadFont (const eFontInfo* fi);

  /// Centers a font between the region "top" and "top + height".  Returns the baseline y-position.
  float CenterVert (float top, float height) {
    // Center the baseline of the text vertically - the 0.2f factor is something
    //  I tried with many different faces and sizes till I found something visually nice.
    return (float)((int)(top + 0.5f * (height + ascent) - 0.2f * descent));
  }

  // Calculates the position to align text within a rectangle
  void TextPos (TCHAR*         szText,            // the text to display
                ePoint*        pos,            // the position that this function will calculate // ePos&
                eGlyphTexRect* rect,       // the rectangle to position the text in
                /*
                GUI_CONSTANTS::alignment_t alignment,   // the alignment of the text within the rectangle
                */
                int* numCharsThatFit);  // the number of characters that can be rendered without overrunning the rectangle

  // Returns the width of the string in pixels
  float StringWidth (const TCHAR* string) {
    float width = 0.0f;

    while (*string != _T ('\0')) {
      width += GetAdvance (*string);
      ++string;
    }

    return width;
  }

  // The height of a string not including the distance between rows
  float StringHeight (void) { return ascent + descent; }

  // Returns an array of size 256 containing all the advances for the characters in this font
  // The is more efficient that using GetAdvance() because of virtual function binding.
////  const float * GetAdvances() { return advances; }

  // Gets the distance to advance the pen for the character 'c'.
  float GetAdvance (TCHAR c) {
    /// TODO: Improve Error Handling (when glyphs is NULL)
    if (c > maxChar)
      return glyphs_ [_T (' ')].advance;

    return glyphs_ [c].advance;
  }

  /// Returns the ascent value for the font, is always positive
  float GetAscent (void) { return ascent; }

  /// Returns the descent value for the font, is always positive
  float GetDescent (void) { return descent; }

  /// Returns the height of the font, from baseline to baseline
  float GetRowHeight (void) { return rowHeight; }

  // Reference counting methods.  I originally tried using a smart pointer class which used these
  // reference counting methods to keep track of number of references for each font.  That didn't work out
  // very well and I wasted like 8 hours coding and uncoding it after.  Right now, the way the font system works
  // is that each widget increments/decrements the references in SetFont() and the widget's dtor.  Its not
  // perfect as an automated smart ptr system would have been, but by making font a private member of iTextMixin
  // we can enforce ref counting.  We just have to remember that (1) for widgets like TextView which don't use SetFont()
  // we need to keep track of refs by manually calling the following methods, and (2) to always call SetFont(NULL)
  // in the dtor of any widgets so we free up any fonts when the widgets are destroyed.
  void IncrementRefs (void) { refCount++; }
  void DecrementRefs (void);
  int  GetNumRefs    (void) { return refCount; }

  e3dTexture* getTex  (void) { return texture_; }
  eFontInfo*  getInfo (void) { return &info_;   }

  // -- old code for using freetype2 - don't delete in case we later need to do a linux port --
  // This function uses freetype2 to create the font
  // returns true on success, faceSize is the size of the EM square in pixels
  //bool LoadFT2(const char * filename, int faceSize, int minChar = 32, int maxChar = 126);

protected:
  friend class eFontStaticsInitializer;

  /// Logging functions
  static void logPrintf          (const TCHAR* szFormat, ...);
  static void logFontCreation    (const eFontInfo* fi, int logID);
  static void logFontDestruction (const eFont* font);
  static void closeFontsLog      (void);
  static void openFontsLog       (void);

  /// The ID that identifies this font in the logfile
  int logFileID;

  /// Teference counting for font handle class
  int refCount;

  /// The log file for fonts
  static FILE* _log;

  /// The UNICODE values of the min & max chars loaded in this font.  It is not possible to load
  /// all the unicode characters as this would take too much memory.  
  int minChar, maxChar;

  /// The max character ascent of the font (always positive)
  float ascent;

  /// The max character descent of the font (always positive)
  float descent;

  /// The distance that should be used between rows of characters of the same font.
  float rowHeight;


  eGlyph* glyphs_;

  // texture ID of the texture containing all the font characters packed as tiny quads
  unsigned int packedTexID;  // TODO: CHANGE to an e3dTexture


  //
  // Memory font specific - If the font height is small enough to fit into the texture cache
  //  the font characters are also stored in memory as an array of unsigned bytes.  This "memory
  //  texture" is then use when rendering to a buffer.  The follow variables are valid only when
  //  the memory font has been loaded. 
  //

  // The glyphs are stored in an 1D array of bytes of size texWidth*texHeight.  There is one
  // byte per pixel which is the alpha value.  The byte offset into the array where a character
  // c starts is given by byteOffsets[c].

  int bitmap_width_;      // Width of the texture in bytes
  int bitmap_height_;

  /*
  // The byte offsets of the characters into memoryTex.  They are stored as consecutive bytes
  // to improve cache coherency.
  int* charOffsets;
  */

  // The memory that holds the font texture
  byte*       bitmap_;
  e3dTexture* texture_;

  eFontInfo   info_;
};



///< Make sure the fonts log gets closed when the game exits
class eFontStaticsInitializer {
public:
   eFontStaticsInitializer (void) { }
  ~eFontStaticsInitializer (void) { eFont::closeFontsLog (); }
};




#endif /* __EPSILON__FONT_H__ */
